#include <cmath>
#include "funkcje.hpp"

double Horner (double tab_wspol[], double arg, int n)
{
//Funkcja obliczajaca wartosc wielomianu
//za pomoca schematu hornera, za parametry przyjmuje
//tablice ze wspolczynnikami, argument oraz dlugosc
//tablicy wspolczynnikow (n)
    double wartosc = 0;

    for (int i = 0; i < n; i++)
    {
        wartosc *= arg;
        wartosc += tab_wspol[i];
    }

    return wartosc;
}

double HornerLiniowy(double x)
{
    return Horner(tab_wspol1, x, n1);
}

double HornerWielomian(double x)
{
     return Horner(tab_wspol2, x, n2);
}

double Sinus(double x)
{
    return sin(x);
}

double SinusZlo(double x)
{
    return sin(Horner(tab_wspol1, x, n1));
}

void WyswietlFunkcje(string funkcje[], int &ktora_funkcja, int nf)
{
    do
    {
        cout<<"Wybierz funkcje:\n";
        for(unsigned int i = 0; i < nf; i++)
        {
            cout<<i+1<<". "<<funkcje[i]<<endl;
        }
        cin>>ktora_funkcja;
    } while(ktora_funkcja < 0 || ktora_funkcja > nf);
}

void PodajPrzedzialOrazDokladnosc(double &a, double &b, double &eps)
{
    do
    {
        cout<<"\nPodaj przedzial calkowania\n";
        cout<<"Podaj lewy kraniec: ";
        cin>>a;
        cout<<"Podaj prawy kraniec: ";
        cin>>b;
    } while(a > b);

    do
    {
        cout<<"\nPodaj dokladnosc: ";
        cin>>eps;
    } while(eps <= 0);
}

double f(int ktora, double x)
{
    return funkcje_tab[ktora - 1](x);
}

double Potega(double podstawa, int wykladnik)
{
    double wynik = 1;

    if(wykladnik == 0)
    {
        return 1;
    }

    for(int i = 0; i < wykladnik; i++)
    {
        wynik *= podstawa;
    }
    return wynik;
}

double Silnia(double a)
{
    double wynik = 1;

    for(int i = 1; i <= a; i++)
    {
        wynik *= i;
    }

    return wynik;
}

double SymbolNewtona(double gora, double dol)
{
    return Silnia(gora)/(Silnia(dol)*Silnia(gora - dol));
}

double NewtonCotes(double a, double b, double eps, int ktora)
{
    double poprzedni_w = 0;
    double wynik;
    double s1, s2;
    double x;
    double h;
    int m = 2;
    bool dalej = true;
    int iteracje = 0;

    while(dalej)
    {
        iteracje++;
        h = (b - a)/m;
        s1 = 0;
        s2 = 0;
        wynik = 0;

        for(int i = 1; i < m; i++)
        {
            x = a + i*h;
            s1 += f(ktora, x);
            s2 += f(ktora, x - h / 2);
        }

        s2 += f(ktora, b - h / 2);
        wynik = (h/6) * (f(ktora, a) + f(ktora, b) + 2*s1 + 4*s2);

        if(abs(poprzedni_w - wynik) > eps)
        {
            poprzedni_w = wynik;
            m *= 2;
        }
        else
        {
            dalej = false;
            cout<<"\nNewton-Cotes wykonal sie "<<iteracje<<" razy.";
            return abs(wynik);
        }
    }
}

double t(double a, double b, double x)
{
    return (a + b) / 2 + (b - a)/2 * x;
}

double Legendre(double a, double b, int ile_w, double Ak[], double Xk[], int ktora)
{
    double h = (b - a) / 2;
    double wynik = 0;

    for(int i = 0; i < ile_w; i++)
    {
        wynik += Ak[i] * f(ktora, t(a, b, Xk[i]));
    }

    return abs(wynik * h);
}
